<?php

namespace app\admin\service;

use app\admin\model\Abnormal;
use app\admin\model\EarlyWarningRule;
use app\admin\model\EarlyWarning;
use app\admin\model\Street;
use app\admin\model\Unit;
use think\Db;

class EarlyWarningService
{
    public function list(): array
    {
        $data = [
            'msg'   => 'success',
            'code'  => 0,
            'data'  => [],
            'count' => EarlyWarning::count('id'),
        ];
        if ($data['count']) {
            $data['data']         = EarlyWarning::order('id', 'desc')
                ->page(PAGE, PERPAGE)
                ->select()
                ->toArray();
            $exceptionCategoryIds = array_column($data['data'], 'exception_category');
            $streetIds            = array_column($data['data'], 'street_id');
            $ruleIds              = array_column($data['data'], 'rule_id');

            $exceptionCategory = Abnormal::where('id', 'in', $exceptionCategoryIds)->select()->toArray();
            $exceptionCategory = array_column($exceptionCategory, null, 'id');
            $exceptionCategory['-4'] = ['model_type' => 'emergency', 'name' => '应急'];
            $exceptionCategory['-3'] = ['model_type' => 'protection', 'name' => '环保'];
            $exceptionCategory['-2'] = ['model_type' => 'way', 'name' => '道路交通'];
            $exceptionCategory['-1'] = ['model_type' => 'illegal', 'name' => '违建'];

            $unitIds           = array_column($exceptionCategory, 'unit_id');
            $units             = Unit::where('id', 'in', $unitIds)->select()->toArray();
            $units             = array_column($units, null, 'id');
            $streets           = Street::where('id', 'in', $streetIds)->select()->toArray();
            $streets           = array_column($streets, null, 'id');
            $rules             = EarlyWarningRule::where('id', 'in', $ruleIds)->select()->toArray();
            $rules             = array_column($rules, null, 'id');
            $moduleMap         = [
                'emergency'  => '应急',
                'way'        => '环保',
                'protection' => '道路交通',
                'illegal'    => '违建'
            ];
            $cycleMap          = [
                1 => '日环比',
                2 => '周环比',
                3 => '月环比'
            ];
            foreach ($data['data'] as &$val) {
                $val['unit']               = $units[$exceptionCategory[$val['exception_category']]['unit_id'] ?? '']['unit_name'] ?? '--';
                $val['city']               = '深圳市龙华区';
                $val['street']             = $streets[$val['street_id']]['name'];
                $val['module']             = $moduleMap[$exceptionCategory[$val['exception_category']]['model_type']];
                $val['level']              = $exceptionCategory[$val['exception_category']]['level'] ?? '顶级';
                $val['exception_category'] = $exceptionCategory[$val['exception_category']]['name'] ?? $val['module'];
                $val['rule_cycle']         = $cycleMap[$rules[$val['rule_id']]['cycle']];
                $val['create_time']        = date('Y-m-d', $val['create_time'] - 86400);
                $val['chain'] = '100%';
                if ($val['last_cycle']) {
                    $val['chain'] = abs(round(($val['last_cycle'] - $val['now_cycle']) / $val['last_cycle'], 4) * 100) . '%';
                }

            }
        }

        return $data;
    }

    public function rule(int $id): array
    {
        $query = EarlyWarningRule::where('mark', 1)
            ->where('exception_category', $id);
        $data  = [
            'msg'   => 'success',
            'code'  => 0,
            'data'  => [],
            'count' => (clone $query)->count('id'),
        ];
        if ($data['count']) {
            $data['data'] = $query->order('id', 'desc')
                ->page(PAGE, PERPAGE)
                ->select()
                ->toArray();
            foreach ($data['data'] as &$val) {
                if ($val['compare'] == 6) {
                    $val['condition'] = array_map('intval', explode(',', $val['condition']));
                }
            }
        }

        return $data;
    }

    public function ruleSave($param, $userId)
    {
        if (empty($param['id'])) {
            $param['create_user'] = $userId;
        } else {
            $param['update_user'] = $userId;
        }
        if ($param['compare'] == 6) {
            $param['condition'] = implode(',', $param['condition']);
        }

        $saveData = [$param];
        if (!empty($param['id'])) {
            $saveData[] = ['id' => $param['id']];
        }
        (new EarlyWarningRule)->allowField(true)->save(...$saveData);
    }


    public function ruleDelete($id)
    {
        EarlyWarningRule::update(['mark' => 0], ['id' => $id]);
    }

    /**
     * @throws \Exception
     */
    public function task()
    {
        //$cycle = [1];
        $cycle = [1, 2, 3];
        if (date('w') == 6) {
            $cycle[] = 2;
        }
        if (date('d') == 1) {
            $cycle[] = 3;
        }
        $rules = (new EarlyWarningRule)
            ->where('mark', 1)
            ->whereIn('cycle', $cycle)
            ->select()
            ->toArray();
        if ($rules) {
            $street  = (new Street)->where('mark', 1)->where('pid', 0)->column('id');
            $service = new OperationService();
            $insert  = [];
            foreach ($rules as $rule) {
                if ($rule['exception_category'] > 0) {
                    $exceptionCategory = (new Abnormal)
                        ->whereRaw('find_in_set(' . $rule['exception_category'] . ', parent_tree)')
                        ->column('id');
                    $exceptionCategory[] = $rule['exception_category'];
                } else {
                    $map = [
                        -4 => 'emergency',
                        -3 => 'protection',
                        -2 => 'way',
                        -1 => 'illegal',
                    ];

                    $exceptionCategory = (new Abnormal)
                        ->where('model_type', $map[$rule['exception_category']])
                        ->column('id');
                }

                list($targetDate, $controlDate) = $this->getDate($rule['cycle']);
                $targetArr  = $service->groupStreet($exceptionCategory, $targetDate);
                $controlArr = $service->groupStreet($exceptionCategory, $controlDate);

                foreach ($street as $streetId) {
                    $target  = $targetArr[$streetId] ?? 0;
                    $control = $controlArr[$streetId] ?? 0;
                    if ($this->compare($target, $control, $rule['compare'], $rule['condition'])) {
                        $insert[] = [
                            'rule_id'            => $rule['id'],
                            'exception_category' => $rule['exception_category'],
                            'street_id'          => $streetId,
                            'now_cycle'          => $target,
                            'last_cycle'         => $control,
                            'feedback'           => $rule['feedback'],
                            'create_time'        => time()
                        ];
                    }
                }
            }
            if ($insert) {
                (new EarlyWarning)->saveAll($insert);
            }
        }
    }

    private function getDate($type): array
    {
        $yesterday = strtotime('yesterday');
        if ($type == 1) {
            return [
                [$yesterday, $yesterday + 86399],
                [$yesterday - 86400, $yesterday - 1],
            ];
        }
        if ($type == 2) {
            return [
                [$yesterday - 6 * 86400, $yesterday + 86399],
                [$yesterday - 13 * 86400, $yesterday - 6 * 86400 - 1],
            ];
        }
        if ($type == 3) {
            $target = [strtotime(date('Y-m-1', $yesterday)), $yesterday + 86399];

            return [
                $target,
                [strtotime(date('Y-m-1', $target[0] - 1)), $target[0] - 1],
            ];
        }

        return [[0, 0], [0, 0]];
    }

    private function compare($target, $control, $compare, $condition): bool
    {
        if (!$target) {
            return false;
        }
        $chain = abs(round(($control - $target) / $target, 4) * 100);
        if ($compare == 1) {
            return $chain > $condition;
        }
        if ($compare == 2) {
            return $chain >= $condition;
        }
        if ($compare == 3) {
            return $chain < $condition;
        }
        if ($compare == 4) {
            return $chain <= $condition;
        }
        if ($compare == 5) {
            return $chain == $condition;
        }
        if ($compare == 6) {
            return $chain >= $condition[0] && $chain <= $condition[1];
        }

        return true;
    }
}
